<?php

namespace app\app\controller;

use app\admin\model\Admin;
use app\admin\model\shop\AdminShopModel;
use app\common\library\Auth;
use app\common\library\Token;
use app\common\model\User;
use fast\Random;
use think\Config;
use think\Controller;
use think\Db;
use think\Exception;
use think\exception\HttpResponseException;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Request;
use think\Response;
use think\Validate;

class AppBase extends Controller
{
    /**
     * 默认响应输出类型,支持json/xml
     * @var string
     */
    protected $responseType = 'json';
    protected $_logined = false; //登录标识
    protected $_error = '';
    protected $_admin = null;
    protected $_shop_id = null;
    protected $_token = '';
    protected $keeptime = 2592000;
    protected $params = [];
    /**
     * 无需登录的方法,同时也就不需要鉴权了
     * @var array
     */
    protected $noNeedLogin = [];

    /**
     * 权限Auth
     * @var Auth
     */
    protected $auth = null;
    protected $allowFields = ['id', 'username', 'nickname', 'avatar', 'avatar', 'loginip',
        'status', 'app_logintime'];

    public function __construct(Request $request = null)
    {

        parent::__construct($request);
    }

    /**
     * 初始化操作
     * @access protected
     */
    protected function _initialize()
    {
        //跨域请求检测
        check_cors_request();
        // 检测IP是否允许
        check_ip_allowed();

        //移除HTML标签
        $this->request->filter('trim,strip_tags,htmlspecialchars');


        $modulename = $this->request->module();
        $controllername = Loader::parseName($this->request->controller());
        $actionname = strtolower($this->request->action());

        // token
        $token = $this->request->server('HTTP_TOKEN', $this->request->request('token', \think\Cookie::get('token')));
        $path = str_replace('.', '/', $controllername) . '/' . $actionname;

        // 检测是否需要验证登录
        if (!$this->match($this->noNeedLogin)) {
            //初始化
            $this->init($token);
            //检测是否登录
            if (!$this->isLogin()) {
                $this->error(__('Please login first'), null, 401);
            }
        } else {
            // 如果有传递token才验证是否登录状态
            if ($token) {
                $this->init($token);
            }
        }

        $upload = \app\common\model\Config::upload();

        // 上传信息配置后
        Hook::listen("upload_config_init", $upload);
        Config::set('upload', array_merge(Config::get('upload'), $upload));

        // 加载当前控制器语言包
        $this->loadlang($controllername);
        $this->params = input('post.');
        $this->params['shop_id'] = $this->_shop_id;
        $this->params['admin_id'] = $this->_admin['id'] ?? null;
    }

    /**
     * 判断是否登录
     * @return boolean
     */
    public function isLogin()
    {
        if ($this->_logined) {
            return true;
        }
        return false;
    }

    /**
     * 操作成功返回的数据
     * @param string $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为1
     * @param string $type 输出类型
     * @param array $header 发送的 Header 信息
     */
    protected function success($msg = '', $data = null, $code = 1, $type = null, array $header = [])
    {
        if (is_array($msg) || is_object($msg)) {
            $data = $msg;
            $msg = 'success';
        } else {
            if ($msg == '') {
                $msg = 'success';
            }
        }
        $this->result($msg, $data, $code, $type, $header);
    }

    /**
     * 操作失败返回的数据
     * @param string $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为0
     * @param string $type 输出类型
     * @param array $header 发送的 Header 信息
     */
    protected function error($msg = '', $data = null, $code = 0, $type = null, array $header = [])
    {
        $this->result($msg, $data, $code, $type, $header);
    }


    /**
     * 返回封装后的 API 数据到客户端
     * @access protected
     * @param mixed $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为0
     * @param string $type 输出类型，支持json/xml/jsonp
     * @param array $header 发送的 Header 信息
     * @return void
     * @throws HttpResponseException
     */
    protected function result($msg, $data = null, $code = 0, $type = null, array $header = [])
    {
        $result = [
            'code' => $code,
            'msg' => $msg,
            'time' => Request::instance()->server('REQUEST_TIME'),
            'data' => $data,
        ];
        // 如果未设置类型则使用默认类型判断
        $type = $type ?: $this->responseType;

        if (isset($header['statuscode'])) {
            $code = $header['statuscode'];
            unset($header['statuscode']);
        } else {
            //未设置状态码,根据code值判断
            $code = $code >= 1000 || $code < 200 ? 200 : $code;
        }
        $response = Response::create($result, $type, $code)->header($header);
        throw new HttpResponseException($response);
    }


    /**
     * 用户登录
     *
     * @param string $account 账号,用户名、邮箱、手机号
     * @param string $password 密码
     * @return boolean
     */
    public function login($account, $password)
    {
        $admin = Admin::where('username', $account)->find();
        if (!$admin) {
            $this->setError('Account is incorrect');
            return false;
        }
        if ($admin->status != 'normal') {
            $this->setError('Account is locked');
            return false;
        }
        if ($admin->app_password != $this->getEncryptPassword($password, $admin->app_salt)) {
            $this->setError('Password is incorrect');
            return false;
        }
        //直接登录
        return $this->direct($admin->id);
    }


    public function direct($admin_id)
    {
        $admin = Admin::get($admin_id);
        if ($admin) {
            Db::startTrans();
            try {
                $ip = request()->ip();
                $time = time();

                $admin->app_logintime = $time;
                //记录本次登录的IP和时间
                $admin->loginip = $ip;
                $admin->logintime = $time;
                //重置登录失败次数
                $admin->loginfailure = 0;

                $admin->save();
                $this->_admin = $admin;
                $this->_token = Random::uuid();
                Token::set($this->_token, $admin->id, $this->keeptime);

                $this->_logined = true;

                $shop = AdminShopModel::alias('a')
                    ->join('shop_message s', 's.id = a.shop_id')
                    ->where('a.admin_id', $admin->id)->field('s.*')->find();

                if (!empty($shop)) {
                    $this->_shop_id = $shop['id'];
                }

                $admin->app_token = $this->_token;
                $admin->save();

                Db::commit();
            } catch (Exception $e) {
                Db::rollback();
                $this->setError($e->getMessage());
                return false;
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取密码加密后的字符串
     * @param string $password 密码
     * @param string $salt 密码盐
     * @return string
     */
    public function getEncryptPassword($password, $salt = '')
    {
        return md5(md5($password) . $salt);
    }


    /**
     * 设置错误信息
     *
     * @param string $error 错误信息
     * @return Auth
     */
    public function setError($error)
    {
        $this->_error = $error;
        return $this;
    }


    /**
     * 检测当前控制器和方法是否匹配传递的数组
     *
     * @param array $arr 需要验证权限的数组
     * @return boolean
     */
    public function match($arr = [])
    {
        $request = Request::instance();
        $arr = is_array($arr) ? $arr : explode(',', $arr);

        if (!$arr) {
            return false;
        }
        $arr = array_map('strtolower', $arr);
        // 是否存在
        if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) {
            return true;
        }
        // 没找到匹配
        return false;
    }

    /**
     * 根据Token初始化
     *
     * @param string $token Token
     * @return boolean
     */
    public function init($token)
    {
        if ($this->_logined) {
            return true;
        }
        if ($this->_error) {
            return false;
        }
        $data = Token::get($token);
        if (!$data) {
            return false;
        }
        $user_id = intval($data['user_id']);

        if ($user_id > 0) {
            $admin = Admin::get($user_id);

            $shop = AdminShopModel::alias('a')
                ->join('shop_message s', 's.id = a.shop_id')
                ->where('a.admin_id', $admin->id)->field('s.*')->find();

            if (!empty($shop)) {
                $this->_shop_id = $shop['id'];
            }


            if (!$admin) {
                $this->setError('Account not exist');
                return false;
            }
            if ($admin['status'] != 'normal') {
                $this->setError('Account is locked');
                return false;
            }
            $this->_admin = $admin;
            $this->_logined = true;
            $this->_token = $token;

            return true;
        } else {
            $this->setError('You are not logged in');
            return false;
        }
    }


    protected function loadlang($name)
    {
        $name = Loader::parseName($name);
        $name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
        $lang = $this->request->langset();
        $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
        Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
    }

    /**
     * 获取会员基本信息
     */
    public function getAdminInfo()
    {
        $data = $this->_admin->toArray();
        $allowFields = $this->getAllowFields();
        $userinfo = array_intersect_key($data, array_flip($allowFields));
        $userinfo = array_merge($userinfo, Token::get($this->_token));
        $userinfo['shop'] = AdminShopModel::alias('a')->join('shop_message s', 's.id = a.shop_id')
            ->where('a.admin_id', $userinfo['id'])->find();
        $userinfo['avatar'] = Https($userinfo['avatar']);
        if (!empty($userinfo['shop'])) {
            $userinfo['shop']['logo_image'] = Https($userinfo['shop']['logo_image']);
        }

        return $userinfo;
    }

    /**
     * 获取允许输出的字段
     * @return array
     */
    public function getAllowFields()
    {
        return $this->allowFields;
    }

    /**
     * 获取错误信息
     * @return string
     */
    public function getError()
    {
        return $this->_error ? __($this->_error) : '';
    }

    /**
     * 退出
     *
     * @return boolean
     */
    public function logout()
    {
        if (!$this->_logined) {
            $this->setError('You are not logged in');
            return false;
        }
        //设置登录标识
        $this->_logined = false;
        //删除Token
        Token::delete($this->_token);
        //退出成功的事件
        return true;
    }

}